//@ts-ignore
import {isEmpty, isFunction, isNotEmpty, isNullOrUnDef} from "./assert";

type Recordable = Record<string,any>;

/**
 * 构建树结构
 * @param arr
 * @param key
 * @param pKey
 * @param filter
 */
export const makeTree = <T extends Recordable & {
    children?: T[]
}>(arr: T[], key: keyof T, pKey: keyof T, filter?: (arg: T) => boolean): T[] => {
    if (isEmpty(arr)) return [];
    const tempMap: Recordable = {};
    for (let i = 0, len = arr.length; i < len; i++) {
        tempMap[arr[i][key] as string] = arr[i];
    }
    const tree: T[] = [];
    for (let i = 0, len = arr.length; i < len; i++) {
        const curr: T = arr[i];
        //@ts-ignore
        if (!isFunction(filter) || filter(curr)) {
            let parent: T = tempMap[curr[pKey] as string];
            if (String(curr[pKey]) === '0') {
                tree.push(curr)
            } else if (isNotEmpty(parent)) {
                if (isNullOrUnDef(parent.children)) {
                    parent.children = [curr]
                } else {
                    //@ts-ignore
                    parent.children.push(curr)
                }
            }
        }
    }
    return tree
}

/**
 * 构建打平的树结构
 * @param arr
 * @param key
 * @param pKey
 * @param filter
 */
export const makeFlatTree = <T extends Recordable & {
    sort?: number
}>(arr: T[], key: keyof T, pKey: keyof T, filter?: (arg: T) => boolean): T[] => {
    if (isEmpty(arr)) return [];
    const tempMap: Recordable = {};
    for (let i = 0, len = arr.length; i < len; i++) {
        tempMap[arr[i][key] as string] = arr[i];
    }
    arr.sort((x: T, y: T) => {
        if (x[pKey] > y[pKey]) return 1;
        if (x[pKey] < y[pKey]) return -1;
        if (!isNullOrUnDef(x['sort']) && !isNullOrUnDef(y['sort'])) {
            //@ts-ignore
            return x['sort'] > y['sort'] ? -1 : 1
        }
        return x[key] > y[key] ? -1 : 1
    })
    const treeIds: string[] = [];
    for (let i = 0, len = arr.length; i < len; i++) {
        const curr = arr[i];
        //@ts-ignore
        if (!isFunction(filter) || filter(curr)) {
            const keyValue = String(curr[key]);
            const parent = tempMap[curr[pKey] as string] ?? null;
            tempMap[keyValue]['is_leaf'] = true;
            if (isEmpty(parent)) {
                tempMap[keyValue]['level'] = 1;
                treeIds.push(keyValue);
            } else {
                const pkeyValue = String(curr[pKey]);
                tempMap[keyValue]['level'] = parent.level + 1;
                tempMap[pkeyValue]['is_leaf'] = false;
                const index = treeIds.indexOf(pkeyValue);
                if (index === 0) {
                    treeIds.unshift(keyValue)
                } else {
                    treeIds.splice(index, 0, keyValue)
                }
            }
        }
    }
    return treeIds.reverse().map((key) => tempMap[key])
}